package com.zh.webcommon.config;

import com.zh.webcommon.common.auth.CollectPermitRequestURI;
import com.zh.webcommon.common.auth.CollectRequestURIScanner;
import com.zh.webcommon.common.auth.LoginUserFillInterceptor;
import com.zh.webcommon.common.auth.annotation.NonePermission;
import com.zh.webcommon.common.exception.MyGlobalExceptionHandler;
import com.zh.webcommon.common.filter.UserHeaderFeignInterceptor;
import com.zh.webcommon.common.log.AccessMonitorAspect;
import com.zh.webcommon.common.log.OperatingLogAspect;
import com.zh.webcommon.common.param.secure.EnsureSafeAspect;
import com.zh.webcommon.common.support.RedisCacheHelper;
import com.zh.webcommon.common.support.SpringContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpMethod;

import java.util.Arrays;

/**
 * @author ZH
 * @date 11:06 2023/5/30
 */
@Slf4j
@Import(value = {SpringContextHolder.class, MyGlobalExceptionHandler.class})
@Configuration(proxyBeanMethods = false)
public class CommonAutoConfigure {
    static {
        log.info("CommonAutoConfigure auto configure ....");
    }

    /**
     * 系统国际化文件配置
     *
     * @return MessageSource
     */
    @Bean
    public MessageSource messageSource() {
        var messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setBasenames("classpath:i18n/messages");
        return messageSource;
    }

    @ConditionalOnBean(RedisTemplate.class)
    @Bean
    public RedisCacheHelper redisCacheHelper(RedisTemplate<String, Object> redisTemplate
            , @Value("${cache.expire-time:60}") int expireTime) {
        return new RedisCacheHelper(redisTemplate, expireTime);
    }

    @Bean
    public OperatingLogAspect operatingLogAspect() {
        return new OperatingLogAspect();
    }

    @ConditionalOnBean(RedisTemplate.class)
    @Bean
    public EnsureSafeAspect idempotentLogAspect(RedisTemplate<String, Object> redisTemplate
            , @Value("${client.appSecret:}") String appSecret) {
        return new EnsureSafeAspect(redisTemplate, appSecret);
    }

    @ConditionalOnProperty(value = "access-monitor.log.enabled", havingValue = "true")
    @Bean
    public AccessMonitorAspect accessMonitorAspect() {
        return new AccessMonitorAspect();
    }

    @ConditionalOnMissingBean(LoginUserFillInterceptor.class)
    @Bean
    public LoginUserFillInterceptor loginUserFillInterceptor() {
        return new LoginUserFillInterceptor();
    }

    @ConditionalOnMissingBean(UserHeaderFeignInterceptor.class)
    @Bean
    public UserHeaderFeignInterceptor userHeaderFeignInterceptor() {
        return new UserHeaderFeignInterceptor();
    }

    /**
     * 扫描被@NonePermission注释的接口方法
     *
     * @return
     */
    @Bean
    public CollectRequestURIScanner collectRequestURIScanner(@Value("${none-permission.url-scanner-package:com.zh.webcommon.config}") String scannerPackage) {
        CollectRequestURIScanner urlScanner = new CollectRequestURIScanner(scannerPackage);
        //查找被@NonePermission注释的接口方法
        urlScanner.setLookFor((url, method) -> {
            NonePermission nonePermission = method.getDeclaredAnnotation(NonePermission.class);
            if (nonePermission != null) {
                Arrays.stream(url.getMethods()).forEach(m -> {
                    CollectPermitRequestURI.addPermitRequestURI(url.getRequestURI(), HttpMethod.valueOf(m.name()));
                });
            }
        });
        //开始扫描
        urlScanner.scanner();
        return urlScanner;
    }
}
